package blocks

import (
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/ethclient"
	"log"
	"math/big"
	"os"
)

// 调用区块链模块

const (
	ETHADDR        = "0xF7A03c7A907ed991fC9884C1EfBCf7B0CE78C78F"
	ACCOUNTKEYPATH = `//home/zf/devdata/keystore/UTC--2022-08-06T07-39-54.806510269Z--6094aaf79f614f577ed111195f5e9ecdfbc96d93`
	ACCOUNTPASSWD  = "12345678"
)

var instance *Task

// TaskMsg 任务信息结构
type TaskMsg struct {
	TaskStatus uint8  `json:"task_status"`
	Bonus      int64  `json:"bonus"`
	Desc       string `json:"task_name"`
	Comment    string `json:"comment"`
	TaskID     string `json:"task_id"`
	Issuer     string `json:"issuer"`
	Worker     string `json:"task_user"`
}

// init 会自动触发运行，只要这个包被调用了，就会自动触发 init 函数的运行，此处用来初始化合约实例
func init() {
	// 链接到合约
	cli, err := ethclient.Dial("http://127.0.0.1:8545")
	if err != nil {
		log.Panic("failed to Dial", err)
	}
	task, err := NewTask(common.HexToAddress(ETHADDR), cli)
	if err != nil {
		log.Panic("failed to NewTask", err)
	}
	// 创建身份
	instance = task
}

func Register(username, passwd string) error {
	// 创建用户身份，需要私钥文件生成
	reader, err := os.Open(ACCOUNTKEYPATH)
	if err != nil {
		fmt.Println("failed to osOpen", err)
		return errors.New(fmt.Sprintf("failed to osOpen:%v", err))
	}
	auth, err := bind.NewTransactor(reader, ACCOUNTPASSWD)
	if err != nil {
		fmt.Println("failed to NewTransactor", err)
		return errors.New(fmt.Sprintf("failed to NewTransactor:%v", err))
	}
	if _, err = instance.Register(auth, username, passwd); err != nil {
		fmt.Println("failed to Register", err)
		return errors.New(fmt.Sprintf("failed to Register:%v", err))
	}
	return nil
}

func Login(username, passwd string) (bool, error) {
	return instance.Login(nil, username, passwd)
}

func Issue(username, passwd, desc string, bonus int64) error {
	// 创建用户身份，需要私钥文件生成
	reader, err := os.Open(ACCOUNTKEYPATH)
	if err != nil {
		fmt.Println("failed to osOpen", err)
		return errors.New(fmt.Sprintf("failed to osOpen:%v", err))
	}
	auth, err := bind.NewTransactor(reader, ACCOUNTPASSWD)
	if err != nil {
		fmt.Println("failed to NewTransactor", err)
		return errors.New(fmt.Sprintf("failed to NewTransactor:%v", err))
	}
	if _, err = instance.Issue(auth, username, passwd, desc, big.NewInt(bonus)); err != nil {
		fmt.Println("failed to Issue", err)
		return errors.New(fmt.Sprintf("failed to Issue:%v", err))
	}
	return nil
}

// Update 修改任务状态，status: 1-接受任务，2-提交，3-确认，4-退回
func Update(username, passwd, comment string, status uint8, taskID int64) error {
	reader, err := os.Open(ACCOUNTKEYPATH)
	if err != nil {
		fmt.Println("failed to osOpen", err)
		return errors.New(fmt.Sprintf("failed to osOpen:%v", err))
	}
	auth, err := bind.NewTransactor(reader, ACCOUNTPASSWD)
	if err != nil {
		fmt.Println("failed to NewTransactor", err)
		return errors.New(fmt.Sprintf("failed to NewTransactor:%v", err))
	}
	switch status {
	case 1:
		if _, err := instance.Take(auth, username, passwd, big.NewInt(taskID)); err != nil {
			fmt.Println("failed to Take task1", err)
			return errors.New(fmt.Sprintf("failed to Take task1:%v", err))
		}
	case 2:
		if _, err := instance.Commit(auth, username, passwd, big.NewInt(taskID)); err != nil {
			fmt.Println("failed to commit task2", err)
			return errors.New(fmt.Sprintf("failed to commit task2:%v", err))
		}
	case 3:
		if _, err := instance.Confirm(auth, username, passwd, big.NewInt(taskID), comment, status); err != nil {
			fmt.Println("failed to Confirm task3", err)
			return errors.New(fmt.Sprintf("failed to Confirm task3:%v", err))
		}
	case 4:
		status = 1
		if _, err := instance.Confirm(auth, username, passwd, big.NewInt(taskID), comment, status); err != nil {
			fmt.Println("failed to Confirm task4", err)
			return errors.New(fmt.Sprintf("failed to Confirm task4:%v", err))
		}
	}
	return nil
}

func TaskList() (tasks []*TaskMsg, err error) {
	taskInfos, err := instance.QryAllTasks(nil)
	if err != nil {
		fmt.Println("failed to QryAllTasks", err)
		return nil, errors.New(fmt.Sprintf("failed to QryAllTasks:%v", err))
	}
	var task TaskMsg
	for k, v := range taskInfos {
		task.TaskID = fmt.Sprintf("%d", k)
		task.Bonus = v.Bonus.Int64()
		task.Comment = v.Comment
		task.Desc = v.Desc
		task.Issuer = v.Issuer
		task.TaskStatus = v.Status
		task.Worker = v.Worker
		tasks = append(tasks, &task)
	}
	return
}
